#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include <string.h>
#include <stdio.h> // 添加此行以支持 MACSTR 和 MAC2STR 宏

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "driver/uart.h"

#include "esp_camera.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"

// WiFi配置 - 热点模式
#define WIFI_SSID "ESP32_Camera"
#define WIFI_PASS "12345678"

#define CAM_PIN_PWDN -1  // power down is not used
#define CAM_PIN_RESET -1 // software reset will be performed
#define CAM_PIN_XCLK 16
#define CAM_PIN_SIOD 5
#define CAM_PIN_SIOC 4

#define CAM_PIN_D7 17
#define CAM_PIN_D6 18
#define CAM_PIN_D5 8
#define CAM_PIN_D4 3
#define CAM_PIN_D3 46
#define CAM_PIN_D2 9
#define CAM_PIN_D1 10
#define CAM_PIN_D0 11
#define CAM_PIN_VSYNC 6
#define CAM_PIN_HREF 7
#define CAM_PIN_PCLK 15

#define WIDTH 320
#define HEIGHT 240
#define ROW_SZ (WIDTH * 2) // 一行 640 字节

static camera_config_t camera_config = {
    .pin_pwdn = CAM_PIN_PWDN,
    .pin_reset = CAM_PIN_RESET,
    .pin_xclk = CAM_PIN_XCLK,
    .pin_sccb_sda = CAM_PIN_SIOD,
    .pin_sccb_scl = CAM_PIN_SIOC,

    .pin_d7 = CAM_PIN_D7,
    .pin_d6 = CAM_PIN_D6,
    .pin_d5 = CAM_PIN_D5,
    .pin_d4 = CAM_PIN_D4,
    .pin_d3 = CAM_PIN_D3,
    .pin_d2 = CAM_PIN_D2,
    .pin_d1 = CAM_PIN_D1,
    .pin_d0 = CAM_PIN_D0,
    .pin_vsync = CAM_PIN_VSYNC,
    .pin_href = CAM_PIN_HREF,
    .pin_pclk = CAM_PIN_PCLK,

    .xclk_freq_hz = 24000000,
    .ledc_timer = LEDC_TIMER_0,
    .ledc_channel = LEDC_CHANNEL_0,

    .pixel_format = PIXFORMAT_RGB565,
    .frame_size = FRAMESIZE_QVGA,

    .jpeg_quality = 12,
    .fb_count = 2,
    .grab_mode = CAMERA_GRAB_WHEN_EMPTY};

static const char *TAG = "camera_server";
static int server_socket = -1;
static int client_socket = -1;

// WiFi事件处理 - SoftAP模式
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
                               int32_t event_id, void *event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STACONNECTED)
    {
        wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;
        ESP_LOGI(TAG, "Station %02x:%02x:%02x:%02x:%02x:%02x joined, AID=%d",
                 event->mac[0], event->mac[1], event->mac[2],
                 event->mac[3], event->mac[4], event->mac[5],
                 event->aid);
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED)
    {
        wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;
        ESP_LOGI(TAG, "Station %02x:%02x:%02x:%02x:%02x:%02x left, AID=%d",
                 event->mac[0], event->mac[1], event->mac[2],
                 event->mac[3], event->mac[4], event->mac[5],
                 event->aid);
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_AP_STAIPASSIGNED)
    {
        ip_event_ap_staipassigned_t *event = (ip_event_ap_staipassigned_t *)event_data;
        ESP_LOGI(TAG, "Assigned IP to station: " IPSTR, IP2STR(&event->ip));
    }
}

// WiFi初始化 - SoftAP模式
static void wifi_init_softap(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t *esp_netif = esp_netif_create_default_wifi_ap();

    // 设置自定义IP地址（可选）
    esp_netif_ip_info_t ip_info;
    IP4_ADDR(&ip_info.ip, 192, 168, 4, 1);
    IP4_ADDR(&ip_info.gw, 192, 168, 4, 1);
    IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
    esp_netif_dhcps_stop(esp_netif);
    esp_netif_set_ip_info(esp_netif, &ip_info);
    esp_netif_dhcps_start(esp_netif);

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_AP_STAIPASSIGNED,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));

    wifi_config_t wifi_config = {
        .ap = {
            .ssid = WIFI_SSID,
            .ssid_len = strlen(WIFI_SSID),
            .password = WIFI_PASS,
            .max_connection = 4,
            .authmode = WIFI_AUTH_WPA2_PSK,
        },
    };

    // 如果没有密码，则设置为开放网络
    if (strlen(WIFI_PASS) == 0)
    {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s",
             WIFI_SSID, WIFI_PASS);
    ESP_LOGI(TAG, "AP IP address: 192.168.4.1");
}

// 相机初始化
esp_err_t camera_init()
{
    // power up the camera if PWDN pin is defined
    if (CAM_PIN_PWDN != -1)
    {
        gpio_config_t io_conf = {
            .pin_bit_mask = 1ULL << CAM_PIN_PWDN,
            .mode = GPIO_MODE_OUTPUT,
            .pull_up_en = GPIO_PULLUP_DISABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
        };
        gpio_config(&io_conf);
        gpio_set_level(CAM_PIN_PWDN, 0);
    }

    // initialize the camera
    esp_err_t err = esp_camera_init(&camera_config);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Camera Init Failed");
        return err;
    }

    return ESP_OK;
}

// TCP服务器初始化
static esp_err_t tcp_server_init(void)
{
    struct sockaddr_in server_addr;

    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket < 0)
    {
        ESP_LOGE(TAG, "Unable to create socket");
        return ESP_FAIL;
    }

    int opt = 1;
    setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(8080);

    int err = bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (err != 0)
    {
        ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
        close(server_socket);
        return ESP_FAIL;
    }

    err = listen(server_socket, 1);
    if (err != 0)
    {
        ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
        close(server_socket);
        return ESP_FAIL;
    }

    ESP_LOGI(TAG, "Socket listening on port 8080");
    return ESP_OK;
}

// 接受客户端连接
static esp_err_t tcp_accept_client(void)
{
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);

    ESP_LOGI(TAG, "Waiting for client connection...");
    client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len);
    if (client_socket < 0)
    {
        ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
        return ESP_FAIL;
    }

    ESP_LOGI(TAG, "Client connected");
    return ESP_OK;
}

// 通过网络发送图像
esp_err_t camera_capture_network(void)
{
    if (client_socket < 0)
    {
        ESP_LOGE(TAG, "No client connected");
        return ESP_FAIL;
    }

    camera_fb_t *fb = esp_camera_fb_get();
    if (!fb)
    {
        ESP_LOGE(TAG, "Camera Capture Failed");
        return ESP_FAIL;
    }

    // 发送元数据
    char meta_str[64];
    int len = sprintf(meta_str, "META,%d,%d,%d\n", ROW_SZ, WIDTH, HEIGHT);
    int sent_len = send(client_socket, meta_str, len, 0);
    if (sent_len < 0)
    {
        ESP_LOGE(TAG, "Failed to send metadata");
        esp_camera_fb_return(fb);
        return ESP_FAIL;
    }

    // 发送图像数据
    int sent = 0;
    while (sent < fb->len)
    {
        int to_send = fb->len - sent;
        if (to_send > 1024)
        {
            to_send = 1024;
        }

        int ret = send(client_socket, fb->buf + sent, to_send, 0);
        if (ret < 0)
        {
            ESP_LOGE(TAG, "Error sending data: errno %d", errno);
            esp_camera_fb_return(fb);
            return ESP_FAIL;
        }
        sent += ret;
    }

    // 发送结束标识
    send(client_socket, "\nEND\n", 5, 0);

    esp_camera_fb_return(fb);
    vTaskDelay(100 / portTICK_PERIOD_MS);

    return ESP_OK;
}

void app_main()
{
    // 初始化NV存储
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    // 初始化WiFi热点
    wifi_init_softap();

    // 初始化TCP服务器
    ESP_ERROR_CHECK(tcp_server_init());

    // 初始化相机
    ESP_ERROR_CHECK(camera_init());

    ESP_LOGI(TAG, "ESP32 Camera Server is ready");
    ESP_LOGI(TAG, "Connect to WiFi network: %s", WIFI_SSID);

    while (1)
    {
        // 接受客户端连接
        if (tcp_accept_client() == ESP_OK)
        {
            // 持续发送图像直到连接断开
            while (1)
            {
                if (camera_capture_network() != ESP_OK)
                {
                    ESP_LOGE(TAG, "Failed to send image, closing connection");
                    break;
                }
                ESP_LOGI(TAG, "Image sent");
                vTaskDelay(100 / portTICK_PERIOD_MS); // 降低发送频率
            }
            close(client_socket);
            client_socket = -1;
            ESP_LOGI(TAG, "Client disconnected");
        }
    }
}